home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / gui.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-01  |  22.1 KB  |  726 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2003 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 2 of the License, or
  9.  *   (at your option) any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   In addition, as a special exception, Michal Trojnara gives
  21.  *   permission to link the code of this program with the OpenSSL
  22.  *   library (or with modified versions of OpenSSL that use the same
  23.  *   license as OpenSSL), and distribute linked combinations including
  24.  *   the two.  You must obey the GNU General Public License in all
  25.  *   respects for all of the code used other than OpenSSL.  If you modify
  26.  *   this file, you may extend this exception to your version of the
  27.  *   file, but you are not obligated to do so.  If you do not wish to
  28.  *   do so, delete this exception statement from your version.
  29.  */
  30.  
  31. #include "common.h"
  32. #include "prototypes.h"
  33. #include <setjmp.h>
  34. #include <windows.h>
  35. #include <windowsx.h>
  36. #include <shellapi.h>
  37. #include "resources.h"
  38.  
  39. #define UWM_SYSTRAY (WM_USER + 1) /* sent to us by the systray */
  40. #define LOG_LINES 250
  41.  
  42. /* Externals */
  43. int unix_main(int, char *[]);
  44.  
  45. /* Prototypes */
  46. static DWORD WINAPI ThreadFunc(LPVOID);
  47. static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
  48.  
  49. static int win_main(HINSTANCE, HINSTANCE, LPSTR, int);
  50. static void save_file(HWND);
  51. static LRESULT CALLBACK about_proc(HWND, UINT, WPARAM, LPARAM);
  52. static LRESULT CALLBACK pass_proc(HWND, UINT, WPARAM, LPARAM);
  53. static char *log_txt(void);
  54. static void set_visible(int);
  55.  
  56. /* NT Service related function */
  57. static int start_service(void);
  58. static int install_service(void);
  59. static int uninstall_service(void);
  60. static void WINAPI service_main(DWORD, LPTSTR *);
  61. static void WINAPI control_handler(DWORD);
  62.  
  63. /* Global variables */
  64. static struct LIST {
  65.   struct LIST *next;
  66.   int len;
  67.   char txt[1]; /* single character for trailing '\0' */
  68. } *head=NULL, *tail=NULL;
  69. static HINSTANCE ghInst;
  70. static HWND EditControl=NULL;
  71. static HMENU htraymenu, hmainmenu;
  72. static HMENU hpopup;
  73. static HWND hwnd=NULL;
  74.  
  75. static char service_path[MAX_PATH];
  76. static SERVICE_STATUS serviceStatus;
  77. static SERVICE_STATUS_HANDLE serviceStatusHandle=0;
  78. static HANDLE stopServiceEvent=0;
  79.  
  80. static int visible=0, error_mode=0;
  81. static jmp_buf jump_buf;
  82.  
  83. static char passphrase[STRLEN];
  84.  
  85. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  86.     LPSTR lpszCmdLine, int nCmdShow) {
  87.  
  88.     char exe_file_name[MAX_PATH], dir[MAX_PATH], *ptr;
  89.     static struct WSAData wsa_state;
  90.  
  91.     ghInst=hInstance;
  92.  
  93.     GetModuleFileName(0, exe_file_name, MAX_PATH);
  94.  
  95.     /* set current directory */
  96.     strcpy(dir, exe_file_name);
  97.     ptr=strrchr(dir, '\\'); /* last backslash */
  98.     if(ptr)
  99.         ptr[1]='\0'; /* truncate program name */
  100.     if(!SetCurrentDirectory(dir)) {
  101.         MessageBox(hwnd, "Cannot set current directory",
  102.             options.win32_name, MB_ICONERROR);
  103.         return 1;
  104.     }
  105.  
  106.     /* setup service_path for CreateService() */
  107.     strcpy(service_path, "\"");
  108.     strcat(service_path, exe_file_name);
  109.     strcat(service_path, "\" -service");
  110.     /* strcat(service_path, lpszCmdLine); */
  111.  
  112.     if(WSAStartup(0x0101, &wsa_state)) {
  113.         win_log("Failed to initialize winsock");
  114.         error_mode=1;
  115.     }
  116.  
  117.     if(!strcmpi(lpszCmdLine, "-service")) {
  118.         if(!setjmp(jump_buf))
  119.             main_initialize(NULL);
  120.         return start_service(); /* Always start service with -service option */
  121.     }
  122.  
  123.     if(!error_mode && !setjmp(jump_buf)) { /* TRY */
  124.         if(!strcmpi(lpszCmdLine, "-install")) {
  125.             main_initialize(NULL);
  126.             return install_service();
  127.         } else if(!strcmpi(lpszCmdLine, "-uninstall")) {
  128.             main_initialize(NULL);
  129.             return uninstall_service();
  130.         } else { /* not -service, -install or -uninstall */
  131.             main_initialize(lpszCmdLine[0] ? lpszCmdLine : NULL);
  132.         }
  133.     }
  134.  
  135.     /* CATCH */
  136.     return win_main(hInstance, hPrevInstance, lpszCmdLine, nCmdShow);
  137. }
  138.  
  139. static int win_main(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  140.         LPSTR lpszCmdLine, int nCmdShow) {
  141.     WNDCLASSEX wc;
  142.     MSG msg;
  143.     char *classname=options.win32_name;
  144.     DWORD iID;
  145.     RECT rect;
  146.  
  147.     /* register the class */
  148.     wc.cbSize=sizeof(WNDCLASSEX);
  149.     wc.style=CS_VREDRAW|CS_HREDRAW;
  150.     wc.lpfnWndProc=wndProc;
  151.     wc.cbClsExtra=wc.cbWndExtra=0;
  152.     wc.hInstance=hInstance;
  153.     wc.hIcon=LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON));
  154.     wc.hCursor=LoadCursor(NULL, IDC_ARROW);
  155.     wc.hbrBackground=(HBRUSH)(COLOR_WINDOW + 1);
  156.     wc.lpszMenuName=NULL;
  157.     wc.lpszClassName=classname;
  158.     wc.hIconSm=LoadImage(hInstance, MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON,
  159.         GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
  160.     RegisterClassEx(&wc);
  161.  
  162.     /* create main window */
  163.     htraymenu=LoadMenu(ghInst, MAKEINTRESOURCE(IDM_TRAYMENU));
  164.     hpopup=GetSubMenu(htraymenu, 0);
  165.     hmainmenu=LoadMenu(ghInst, MAKEINTRESOURCE(IDM_MAINMENU));
  166.     hwnd=CreateWindow(classname, options.win32_name, WS_TILEDWINDOW,
  167.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  168.         NULL, hmainmenu, hInstance, NULL);
  169.  
  170.     /* create child edit window */
  171.     EditControl=CreateWindow ("EDIT", NULL,
  172.         WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_READONLY,
  173.         0, 0, 0, 0, hwnd, NULL, hInstance, NULL);
  174.     SendMessage(EditControl, WM_SETFONT, (WPARAM)GetStockObject(OEM_FIXED_FONT),
  175.         MAKELPARAM(FALSE, 0)); /* no need to redraw right, now */
  176.     GetClientRect(hwnd, &rect);
  177.     MoveWindow(EditControl, 0, 0, rect.right, rect.bottom, TRUE);
  178.     SetFocus(EditControl);
  179.  
  180.     if(error_mode) /* log window is hidden by default */
  181.         set_visible(1);
  182.     else /* create the main thread */
  183.         CloseHandle(CreateThread(NULL, 0, ThreadFunc, NULL, 0, &iID));
  184.  
  185.     while (GetMessage(&msg, NULL, 0, 0)) {
  186.         TranslateMessage(&msg);
  187.         DispatchMessage(&msg);
  188.     }
  189.  
  190.     return msg.wParam;
  191. }
  192.  
  193. static void update_systray(void) { /* create the systray icon */
  194.     NOTIFYICONDATA nid;
  195.  
  196.     nid.cbSize=sizeof(NOTIFYICONDATA); /* size */
  197.     nid.hWnd=hwnd; /* window to receive notifications */
  198.     nid.uID=1;     /* application-defined ID for icon */
  199.     if(error_mode)
  200.         strcpy(nid.szTip, "Server is down");
  201.     else
  202.         sprintf(nid.szTip, "%d session(s) active", num_clients);
  203.     nid.uFlags=NIF_TIP;
  204.     /* only nid.szTip and nid.uID are valid, change tip */
  205.     if(Shell_NotifyIcon(NIM_MODIFY, &nid)) /* modify tooltip */
  206.         return; /* OK: systray icon exists */
  207.  
  208.     /* trying to update tooltip failed - lets try to create the icon */
  209.     nid.uFlags=NIF_MESSAGE | NIF_ICON | NIF_TIP;
  210.     nid.uCallbackMessage=UWM_SYSTRAY;
  211.     nid.hIcon=LoadImage(ghInst, MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON,
  212.         GetSystemMetrics(SM_CXSMICON),
  213.         GetSystemMetrics(SM_CYSMICON), 0); /* 16x16 icon */
  214.     Shell_NotifyIcon(NIM_ADD, &nid); /* this adds the icon */
  215. }
  216.  
  217. static DWORD WINAPI ThreadFunc(LPVOID arg) {
  218.     if(!setjmp(jump_buf))
  219.         main_execute();
  220.     else
  221.         set_visible(1); /* could be unsafe to call it from another thread */
  222.     return 0;
  223. }
  224.  
  225. static LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  226.     POINT pt;
  227.     NOTIFYICONDATA nid;
  228.     RECT rect;
  229.     char *txt;
  230.  
  231. #if 0
  232.     if(message!=WM_CTLCOLORSTATIC && message!=WM_TIMER)
  233.         log(LOG_DEBUG, "Window message: %d", message);
  234. #endif
  235.     switch (message) {
  236.     case WM_CREATE:
  237.         SetTimer(hwnd, 0x29a, 1000, NULL); /* 1-second timer */
  238.         return TRUE;
  239.  
  240.     case WM_SIZE:
  241.         GetClientRect(hwnd, &rect);
  242.         MoveWindow(EditControl, 0, 0, rect.right, rect.bottom, TRUE);
  243.         UpdateWindow(EditControl);
  244.         return TRUE;
  245.  
  246.     case WM_SETFOCUS:
  247.         txt=log_txt();
  248.         SetWindowText(EditControl, txt);
  249.         free(txt);
  250.         SetFocus(EditControl);
  251.         return TRUE;
  252.  
  253.     case WM_TIMER:
  254.         update_systray();
  255.         return TRUE;
  256.  
  257.     case WM_CLOSE:
  258.         set_visible(0);
  259.         return TRUE;
  260.  
  261.     case WM_DESTROY:
  262.         DestroyMenu(hmainmenu);
  263.         DestroyMenu(htraymenu);
  264.         nid.cbSize=sizeof(NOTIFYICONDATA);
  265.         nid.hWnd=hwnd;
  266.         nid.uID=1;
  267.         nid.uFlags=NIF_TIP; /* not really sure what to put here, but it works */
  268.         Shell_NotifyIcon(NIM_DELETE, &nid); /* this removes the icon */
  269.         PostQuitMessage(0);
  270.         KillTimer(hwnd, 0x29a);
  271.         return TRUE;
  272.  
  273.     case WM_COMMAND:
  274.         switch(wParam) {
  275.         case IDM_ABOUT:
  276.             DialogBox(ghInst, "AboutBox", hwnd, (DLGPROC)about_proc);
  277.             break;
  278.         case IDM_LOG:
  279.             set_visible(!visible);
  280.             break;
  281.         case IDM_CLOSE:
  282.             set_visible(0);
  283.             break;
  284.         case IDM_EXIT:
  285.             DestroyWindow(hwnd);
  286.             break;
  287.         case IDM_SAVEAS:
  288.             save_file(hwnd);
  289.             break;
  290.         case IDM_SETUP:
  291.             MessageBox(hwnd, "Function not implemented",
  292.                 options.win32_name, MB_ICONERROR);
  293.             break;
  294.         };
  295.         return TRUE;
  296.  
  297.     case UWM_SYSTRAY:
  298.         switch (lParam) {
  299.         case WM_RBUTTONUP: /* track a popup menu */
  300.             /* http://support.microsoft.com/support/kb/articles/Q135/7/88.asp */
  301.             GetCursorPos(&pt);
  302.             SetForegroundWindow(hwnd);
  303.             TrackPopupMenu(hpopup, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
  304.             PostMessage(hwnd, WM_NULL, 0, 0); /* see above */
  305.             break;
  306.         case WM_LBUTTONDBLCLK: /* switch log window visibility */
  307.             set_visible(!visible);
  308.             break;
  309.         }
  310.         return TRUE;
  311.     }
  312.     return DefWindowProc(hwnd, message, wParam, lParam);
  313. }
  314.  
  315. static LRESULT CALLBACK about_proc(HWND hDlg, UINT message,
  316.         WPARAM wParam, LPARAM lParam) {
  317.     switch(message) {
  318.         case WM_INITDIALOG:
  319.             return TRUE;
  320.         case WM_COMMAND:
  321.             switch(wParam) {
  322.                 case IDOK:
  323.                 case IDCANCEL:
  324.                     EndDialog(hDlg, TRUE);
  325.                     return TRUE;
  326.             }
  327.     }
  328.     return FALSE;
  329. }
  330.  
  331. static LRESULT CALLBACK pass_proc(HWND hDlg, UINT message,
  332.         WPARAM wParam, LPARAM lParam) {
  333.     char titlebar[STRLEN];
  334.     WORD cchPassword;
  335.  
  336.     switch (message) {
  337.     case WM_INITDIALOG:
  338.         /* Set the default push button to "Cancel." */
  339.         SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDCANCEL, (LPARAM) 0);
  340.  
  341.         safecopy(titlebar, "Private key: ");
  342.         safeconcat(titlebar, options.key);
  343.         SetWindowText(hDlg, titlebar);
  344.         return TRUE;
  345.  
  346.     case WM_COMMAND:
  347.         /* Set the default push button to "OK" when the user enters text. */
  348.         if(HIWORD (wParam) == EN_CHANGE && LOWORD(wParam) == IDE_PASSWORDEDIT)
  349.             SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDOK, (LPARAM) 0);
  350.         switch(wParam) {
  351.         case IDOK:
  352.             /* Get number of characters. */
  353.             cchPassword = (WORD) SendDlgItemMessage(hDlg,
  354.                 IDE_PASSWORDEDIT, EM_LINELENGTH, (WPARAM) 0, (LPARAM) 0);
  355.             if(cchPassword==0 || cchPassword>=STRLEN) {
  356.                 EndDialog(hDlg, FALSE);
  357.                 return FALSE;
  358.             }
  359.  
  360.             /* Put the number of characters into first word of buffer. */
  361.             *((LPWORD)passphrase) = cchPassword;
  362.  
  363.             /* Get the characters. */
  364.             SendDlgItemMessage(hDlg, IDE_PASSWORDEDIT, EM_GETLINE,
  365.                 (WPARAM) 0, /* line 0 */ (LPARAM) passphrase);
  366.  
  367.             passphrase[cchPassword] = 0; /* Null-terminate the string. */
  368.             EndDialog(hDlg, TRUE);
  369.             return TRUE;
  370.  
  371.         case IDCANCEL:
  372.             EndDialog(hDlg, FALSE);
  373.             return TRUE;
  374.         }
  375.         return 0;
  376.     }
  377.     return FALSE;
  378.  
  379.     UNREFERENCED_PARAMETER(lParam);
  380. }
  381.  
  382. int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
  383.     int result;
  384. #if 0
  385.     DWORD dwThreadId;
  386.     HWINSTA hwinstaSave;
  387.     HDESK hdeskSave;
  388.     HWINSTA hwinstaUser;
  389.     HDESK hdeskUser;
  390.  
  391.     buf[0]='\0'; /* empty the buffer */
  392.  
  393.     /* Save the window station and desktop */
  394.     hwinstaSave=GetProcessWindowStation();
  395.     if(!hwinstaSave)
  396.         ioerror("GetProcessWindowStation");
  397.     dwThreadId=GetCurrentThreadId();
  398.     if(!dwThreadId)
  399.         ioerror("GetCurrentThreadId");
  400.     hdeskSave=GetThreadDesktop(dwThreadId);
  401.     if(!hdeskSave)
  402.         ioerror("GetThreadDesktop");
  403.  
  404.     /* Switch to WinSta0/Default */
  405.     hwinstaUser=OpenWindowStation("winsta0", FALSE, MAXIMUM_ALLOWED);
  406.     if(!hwinstaUser)
  407.         ioerror("OpenWindowStation");
  408.     if(!SetProcessWindowStation(hwinstaUser))
  409.         ioerror("SetProcessWindowStation");
  410.     hdeskUser=OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED); /* Winlogon */
  411.     if(!hdeskUser)
  412.         ioerror("OpenDesktop");
  413.     if(!SetThreadDesktop(hdeskUser))
  414.         ioerror("SetThreadDesktop");
  415. #endif
  416.  
  417.     /* Display the dialog box */
  418.     result=DialogBox(ghInst, "PassBox", hwnd, (DLGPROC)pass_proc);
  419.  
  420. #if 0
  421.     /* Restore window station and desktop */
  422.     if(!SetThreadDesktop(hdeskSave))
  423.         ioerror("SetThreadDesktop");
  424.     if(!SetProcessWindowStation(hwinstaSave))
  425.         ioerror("SetProcessWindowStation");
  426.     if(!CloseDesktop(hdeskUser))
  427.         ioerror("CloseDesktop");
  428.     if(!CloseWindowStation(hwinstaUser))
  429.         ioerror("CloseWindowStation");
  430. #endif
  431.  
  432.     if(!result)
  433.         return 0;
  434.     strncpy(buf, passphrase, size);
  435.     buf[size - 1] = '\0';
  436.     return strlen(buf);
  437. }
  438.  
  439. static void save_file(HWND hwnd) {
  440.     char szFileName[MAX_PATH];
  441.     OPENFILENAME ofn;
  442.     HANDLE hFile;
  443.     BOOL bResult;
  444.     char *txt;
  445.     DWORD nToWrite, nWritten;
  446.  
  447.     ZeroMemory(&ofn, sizeof(ofn));
  448.     szFileName[0]='\0';
  449.  
  450.     ofn.lStructSize=sizeof(ofn);
  451.     ofn.hwndOwner=hwnd;
  452.     ofn.lpstrFilter="Log Files (*.log)\0*.log\0All Files (*.*)\0*.*\0\0";
  453.     ofn.lpstrFile=szFileName;
  454.     ofn.nMaxFile=MAX_PATH;
  455.     ofn.lpstrDefExt="LOG";
  456.     ofn.lpstrInitialDir=".";
  457.  
  458.     ofn.lpstrTitle="Save Log";
  459.     ofn.Flags=OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
  460.         OFN_OVERWRITEPROMPT;
  461.     if(!GetSaveFileName(&ofn))
  462.         return;
  463.  
  464.     if((hFile=CreateFile((LPCSTR)szFileName, GENERIC_WRITE,
  465.             0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  466.             (HANDLE) NULL))==INVALID_HANDLE_VALUE) {
  467.         MessageBox(hwnd, "File open failed", options.win32_name, MB_ICONERROR);
  468.         return;
  469.     }
  470.  
  471.     txt=log_txt();
  472.     nToWrite=strlen(txt);
  473.     bResult=WriteFile(hFile, txt, nToWrite, &nWritten, NULL);
  474.     free(txt);
  475.     if(!bResult)
  476.         MessageBox(hwnd, "File write failed", options.win32_name, MB_ICONERROR);
  477.     CloseHandle(hFile);
  478. }
  479.  
  480. void win_log(char *line) { /* Also used in log.c */
  481.     struct LIST *curr;
  482.     int len;
  483.     static int log_len=0;
  484.     char *txt;
  485.  
  486.     len=strlen(line);
  487.     curr=malloc(sizeof(struct LIST)+len);
  488.     curr->len=len;
  489.     strcpy(curr->txt, line);
  490.     curr->next=NULL;
  491.  
  492.     enter_critical_section(CRIT_WIN_LOG);
  493.     if(tail)
  494.         tail->next=curr;
  495.     tail=curr;
  496.     if(!head)
  497.         head=tail;
  498.     log_len++;
  499.     while(log_len>LOG_LINES) {
  500.         curr=head;
  501.         head=head->next;
  502.         free(curr);
  503.         log_len--;
  504.     }
  505.     leave_critical_section(CRIT_WIN_LOG);
  506.  
  507.     if(visible) {
  508.         txt=log_txt();
  509.         SetWindowText(EditControl, txt);
  510.         free(txt);
  511.     }
  512. }
  513.  
  514. static char *log_txt(void) {
  515.     char *buff;
  516.     int ptr=0, len=0;
  517.     struct LIST *curr;
  518.  
  519.     enter_critical_section(CRIT_WIN_LOG);
  520.     for(curr=head; curr; curr=curr->next)
  521.         len+=curr->len+2; /* +2 for trailing '\r\n' */
  522.     buff=malloc(len+1); /* +1 for trailing '\0' */
  523.     for(curr=head; curr; curr=curr->next) {
  524.         memcpy(buff+ptr, curr->txt, curr->len);
  525.         ptr+=curr->len;
  526.         if(curr->next) {
  527.             buff[ptr++]='\r';
  528.             buff[ptr++]='\n';
  529.         }
  530.     }
  531.     buff[ptr]='\0';
  532.     leave_critical_section(CRIT_WIN_LOG);
  533.  
  534.     return buff;
  535. }
  536.  
  537. static void set_visible(int i) {
  538.     char *txt;
  539.  
  540.     visible=i; /* setup global variable */
  541.     CheckMenuItem(hpopup, GetMenuItemID(hpopup, 1),
  542.         visible?MF_CHECKED:MF_UNCHECKED); /* check or uncheck menu item */
  543.     if(visible) {
  544.         txt=log_txt();
  545.         SetWindowText(EditControl, txt); /* setup window content */
  546.         free(txt);
  547.         ShowWindow(hwnd, SW_SHOWNORMAL); /* show window */
  548.         SetForegroundWindow(hwnd); /* bring on top */
  549.     } else
  550.         ShowWindow(hwnd, SW_HIDE); /* hide window */
  551. }
  552.  
  553. void exit_stunnel(int code) { /* used instead of exit() on Win32 */
  554.     win_log("");
  555.     log(LOG_ERR, "Server is down");
  556.     MessageBox(hwnd, "Stunnel server is down due to an error.\n"
  557.         "You need to exit and correct the problem.\n"
  558.         "Click OK to see the error log window.",
  559.         options.win32_service, MB_ICONERROR);
  560.     error_mode=1;
  561.     longjmp(jump_buf, 1);
  562. }
  563.  
  564. static int start_service(void) {
  565.     SERVICE_TABLE_ENTRY serviceTable[]={
  566.         {options.win32_service, service_main},
  567.         {0, 0}
  568.     };
  569.  
  570.     if(!StartServiceCtrlDispatcher(serviceTable)) {
  571.         MessageBox(hwnd, "Unable to start the service",
  572.             options.win32_service, MB_ICONERROR);
  573.         return 1;
  574.     }
  575.     return 0; /* NT service started */
  576. }
  577.  
  578. static int install_service(void) {
  579.     SC_HANDLE scm, service;
  580.  
  581.     scm=OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
  582.     if(!scm) {
  583.         MessageBox(hwnd, "Failed to open service control manager",
  584.             options.win32_service, MB_ICONERROR);
  585.         return 1;
  586.     }
  587.     service=CreateService(scm,
  588.         options.win32_service, options.win32_service, SERVICE_ALL_ACCESS,
  589.         SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
  590.         SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, service_path,
  591.         NULL, NULL, NULL, NULL, NULL);
  592.     if(!service) {
  593.         MessageBox(hwnd, "Failed to create a new service",
  594.             options.win32_service, MB_ICONERROR);
  595.         CloseServiceHandle(scm);
  596.         return 1;
  597.     }
  598.     MessageBox(hwnd, "Service installed", options.win32_service,
  599.         MB_ICONINFORMATION);
  600.     CloseServiceHandle(service);
  601.     CloseServiceHandle(scm);
  602.     return 0;
  603. }
  604.  
  605. static int uninstall_service(void) {
  606.     SC_HANDLE scm, service;
  607.     SERVICE_STATUS serviceStatus;
  608.  
  609.     scm=OpenSCManager(0, 0, SC_MANAGER_CONNECT);
  610.     if(!scm) {
  611.         MessageBox(hwnd, "Failed to open service control manager",
  612.             options.win32_service, MB_ICONERROR);
  613.         return 1;
  614.     }
  615.     service=OpenService(scm, options.win32_service,
  616.         SERVICE_QUERY_STATUS | DELETE);
  617.     if(!service) {
  618.         MessageBox(hwnd, "Failed to open the service",
  619.             options.win32_service, MB_ICONERROR);
  620.         CloseServiceHandle(scm);
  621.         return 1;
  622.     }
  623.     if(!QueryServiceStatus(service, &serviceStatus)) {
  624.         MessageBox(hwnd, "Failed to query service status",
  625.             options.win32_service, MB_ICONERROR);
  626.         CloseServiceHandle(service);
  627.         CloseServiceHandle(scm);
  628.         return 1;
  629.     }
  630.     if(serviceStatus.dwCurrentState!=SERVICE_STOPPED) {
  631.         MessageBox(hwnd, "The service is still running",
  632.             options.win32_service, MB_ICONERROR);
  633.         CloseServiceHandle(service);
  634.         CloseServiceHandle(scm);
  635.         return 1;
  636.     }
  637.     if(!DeleteService(service)) {
  638.         MessageBox(hwnd, "Failed to delete the service",
  639.             options.win32_service, MB_ICONERROR);
  640.         CloseServiceHandle(service);
  641.         CloseServiceHandle(scm);
  642.         return 1;
  643.     }
  644.     MessageBox(hwnd, "Service uninstalled", options.win32_service,
  645.         MB_ICONINFORMATION);
  646.     CloseServiceHandle(service);
  647.     CloseServiceHandle(scm);
  648.     return 0;
  649. }
  650.  
  651. static void WINAPI service_main(DWORD argc, LPTSTR* argv) {
  652.     /* initialise service status */
  653.     serviceStatus.dwServiceType=SERVICE_WIN32;
  654.     serviceStatus.dwCurrentState=SERVICE_STOPPED;
  655.     serviceStatus.dwControlsAccepted=0;
  656.     serviceStatus.dwWin32ExitCode=NO_ERROR;
  657.     serviceStatus.dwServiceSpecificExitCode=NO_ERROR;
  658.     serviceStatus.dwCheckPoint=0;
  659.     serviceStatus.dwWaitHint=0;
  660.  
  661.     serviceStatusHandle=
  662.         RegisterServiceCtrlHandler(options.win32_service, control_handler);
  663.  
  664.     if(serviceStatusHandle) {
  665.         /* service is starting */
  666.         serviceStatus.dwCurrentState=SERVICE_START_PENDING;
  667.         SetServiceStatus(serviceStatusHandle, &serviceStatus);
  668.  
  669.         /* do initialisation here */
  670.         stopServiceEvent=CreateEvent(0, FALSE, FALSE, 0);
  671.  
  672.         /* running */
  673.         serviceStatus.dwControlsAccepted|=
  674.             (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
  675.         serviceStatus.dwCurrentState=SERVICE_RUNNING;
  676.         SetServiceStatus(serviceStatusHandle, &serviceStatus);
  677.  
  678.         win_main(ghInst, NULL, "", 0);
  679.  
  680.         /* service was stopped */
  681.         serviceStatus.dwCurrentState=SERVICE_STOP_PENDING;
  682.         SetServiceStatus(serviceStatusHandle, &serviceStatus);
  683.  
  684.         /* do cleanup here */
  685.         CloseHandle(stopServiceEvent);
  686.         stopServiceEvent=0;
  687.  
  688.         /* service is now stopped */
  689.         serviceStatus.dwControlsAccepted&=
  690.             ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
  691.         serviceStatus.dwCurrentState=SERVICE_STOPPED;
  692.         SetServiceStatus(serviceStatusHandle, &serviceStatus);
  693.     }
  694. }
  695.  
  696. static void WINAPI control_handler(DWORD controlCode) {
  697.     switch (controlCode) {
  698.     case SERVICE_CONTROL_INTERROGATE:
  699.         break;
  700.  
  701.     case SERVICE_CONTROL_SHUTDOWN:
  702.     case SERVICE_CONTROL_STOP:
  703.         serviceStatus.dwCurrentState=SERVICE_STOP_PENDING;
  704.         SetServiceStatus(serviceStatusHandle, &serviceStatus);
  705.         PostMessage(hwnd, WM_COMMAND, IDM_EXIT, 0);
  706.         SetEvent(stopServiceEvent);
  707.         return;
  708.  
  709.     case SERVICE_CONTROL_PAUSE:
  710.         break;
  711.  
  712.     case SERVICE_CONTROL_CONTINUE:
  713.         break;
  714.  
  715.     default:
  716.         if(controlCode >= 128 && controlCode <= 255)
  717.             break; /* user defined control code */
  718.         else
  719.             break; /* unrecognised control code */
  720.     }
  721.  
  722.     SetServiceStatus(serviceStatusHandle, &serviceStatus);
  723. }
  724.  
  725. /* End of gui.c */
  726.